package com.xdcplus.web.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.xdcplus.exceptions.ResponseUtils;
import com.xdcplus.exceptions.domain.ResponseVO;
import com.xdcplus.mdm.api.PmShiftPlanRemote;
import com.xdcplus.mdm.api.vo.PmShiftManageWithPlanVO;
import com.xdcplus.mom.constants.NumberConstant;
import com.xdcplus.mom.enums.ResponseEnum;
import com.xdcplus.exceptions.XdcWebException;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.collection.CollectionUtil;

import com.xdcplus.mom.pojo.dto.getui.GtPushDTO;
import com.xdcplus.mom.pojo.dto.getui.PushBatchByAliasDto;
import com.xdcplus.mom.pojo.dto.getui.PushBatchByAliasItem;
import com.xdcplus.mp.service.impl.BaseServiceImpl;
import com.xdcplus.sms.api.SmsRemote;
import com.xdcplus.web.common.pojo.bo.OpeJobTaskAlarmCodeSettingBO;
import com.xdcplus.web.common.pojo.dto.OpeJobTaskStaffingFilterDTO;
import com.xdcplus.web.common.pojo.dto.sms.SmsDTO;
import com.xdcplus.web.common.pojo.dto.task.JobTaskAlarmCodeDTO;
import com.xdcplus.web.common.pojo.dto.task.JobTaskEapDTO;
import com.xdcplus.web.common.pojo.vo.OpeJobTaskRecordEO;
import com.xdcplus.web.common.pojo.vo.OpeJobTaskStaffingVO;
import com.xdcplus.web.mapper.OpeJobTaskRecordMapper;
import com.xdcplus.web.common.pojo.entity.OpeJobTaskRecord;
import com.xdcplus.web.common.pojo.dto.OpeJobTaskRecordDTO;
import com.xdcplus.web.common.pojo.dto.OpeJobTaskRecordFilterDTO;
import com.xdcplus.web.common.pojo.vo.OpeJobTaskRecordVO;
import com.xdcplus.web.common.pojo.query.OpeJobTaskRecordQuery;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.pager.vo.PageVO;
import com.xdcplus.mp.utils.PageableUtils;
import com.xdcplus.mp.utils.PropertyUtils;
import com.xdcplus.web.service.OpeJobTaskStaffingService;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;

import com.xdcplus.web.service.OpeJobTaskRecordService;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
 * (OpeJobTaskRecord)表服务实现类
 *
 * @author Zhecheng.Ren
 * @since 2024-10-30 14:52:12
 */
@Slf4j
@Service("opeJobTaskRecordService")
public class OpeJobTaskRecordServiceImpl extends BaseServiceImpl<OpeJobTaskRecordMapper, OpeJobTaskRecord, OpeJobTaskRecord, OpeJobTaskRecordVO> implements OpeJobTaskRecordService {

    @Resource
    protected OpeJobTaskRecordMapper opeJobTaskRecordMapper;
    @Resource
    private PmShiftPlanRemote pmShiftPlanRemote;
    @Resource
    private OpeJobTaskStaffingService opeJobTaskStaffingService;
    @Resource
    private SmsRemote smsRemote;

    private final static DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveOpeJobTaskRecord(OpeJobTaskRecordDTO opeJobTaskRecordDTO) {

        OpeJobTaskRecord opeJobTaskRecord = new OpeJobTaskRecord();
        BeanUtil.copyProperties(opeJobTaskRecordDTO, opeJobTaskRecord);
        opeJobTaskRecord.setCreatedTime(new Timestamp(DateUtil.current()));

        return this.save(opeJobTaskRecord);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean updateOpeJobTaskRecord(OpeJobTaskRecordDTO opeJobTaskRecordDTO) {

        OpeJobTaskRecord opeJobTaskRecord = this.getById(opeJobTaskRecordDTO.getId());
        if (ObjectUtil.isNull(opeJobTaskRecord)) {
            log.error("updateOpeJobTaskRecord() The OpeJobTaskRecord does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }

        BeanUtil.copyProperties(opeJobTaskRecordDTO, opeJobTaskRecord);
        opeJobTaskRecord.setUpdatedUser(opeJobTaskRecordDTO.getUpdatedUser());
        opeJobTaskRecord.setUpdatedTime(new Timestamp(DateUtil.current()));

        return this.updateById(opeJobTaskRecord);
    }

    @Override
    public Boolean saveOrUpdateBatch(List<OpeJobTaskRecord> opeJobTaskRecordList) {

        opeJobTaskRecordList.forEach(opeJobTaskRecord -> {
            OpeJobTaskRecord opeJobTaskRecordParam = new OpeJobTaskRecord();
            opeJobTaskRecordParam.setId(opeJobTaskRecord.getId());
            if (ObjectUtil.isNotNull(opeJobTaskRecord.getId())) {
                opeJobTaskRecord.setId(opeJobTaskRecord.getId());
                opeJobTaskRecord.setUpdatedTime(new Timestamp(DateUtil.current()));
                LambdaUpdateWrapper<OpeJobTaskRecord> lambdaUpdate = Wrappers.lambdaUpdate();
                lambdaUpdate.eq(OpeJobTaskRecord::getId, opeJobTaskRecord.getId());
                update(opeJobTaskRecord, lambdaUpdate);
            } else {
                opeJobTaskRecord.setCreatedTime(new Timestamp(DateUtil.current()));
                save(opeJobTaskRecord);
            }
        });
        return true;
    }

    @Override
    public Boolean saveOrUpdateBatchByDTOList(List<OpeJobTaskRecordDTO> opeJobTaskRecordDTOList) {

        List<OpeJobTaskRecord> opeJobTaskRecordList = BeanUtils.copyProperties(opeJobTaskRecordDTOList, OpeJobTaskRecord.class);
        return saveOrUpdateBatch(opeJobTaskRecordList);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteOpeJobTaskRecordLogical(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        OpeJobTaskRecord opeJobTaskRecord = this.getById(id);

        if (ObjectUtil.isNull(opeJobTaskRecord)) {
            log.error("deleteOpeJobTaskRecord() The OpeJobTaskRecord does not exist or has been deleted");
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        return this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean deleteOpeJobTaskRecordByIds(String ids) {
        Assert.notNull(ids, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());
        List<String> idList = Arrays.asList(ids.split(","));
        if (CollectionUtil.isEmpty(idList)) {
            throw new XdcWebException(ResponseEnum.ERROR);
        }
        idList.forEach(id -> {
            OpeJobTaskRecord opeJobTaskRecord = this.getById(id);
            if (ObjectUtil.isNull(opeJobTaskRecord)) {
                log.error("deleteOpeJobTaskRecord() The OpeJobTaskRecord does not exist or has been deleted");
                throw new XdcWebException(ResponseEnum.ERROR);
            }
        });

        return this.removeByIds(idList);
    }

    private List<OpeJobTaskRecordVO> queryOpeJobTaskRecordList(OpeJobTaskRecordFilterDTO opeJobTaskRecordFilterDTO) {
        OpeJobTaskRecordQuery opeJobTaskRecordQuery = BeanUtil.copyProperties(opeJobTaskRecordFilterDTO, OpeJobTaskRecordQuery.class);

        return opeJobTaskRecordMapper.queryOpeJobTaskRecord(opeJobTaskRecordQuery);
    }

    @Override
    public List<OpeJobTaskRecordVO> queryOpeJobTaskRecordVOList(OpeJobTaskRecordFilterDTO opeJobTaskRecordFilterDTO) {
        return queryOpeJobTaskRecordList(opeJobTaskRecordFilterDTO);
    }

    @Override
    public PageVO<OpeJobTaskRecordVO> queryOpeJobTaskRecord(OpeJobTaskRecordFilterDTO opeJobTaskRecordFilterDTO) {
        PageVO<OpeJobTaskRecordVO> pageVO = new PageVO<>();

        if (opeJobTaskRecordFilterDTO.getCurrentPage() > NumberConstant.ZERO) {
            PageableUtils.basicPage(opeJobTaskRecordFilterDTO.getCurrentPage(), opeJobTaskRecordFilterDTO.getPageSize(),
                    opeJobTaskRecordFilterDTO.getOrderType(), opeJobTaskRecordFilterDTO.getOrderField());
        }

        List<OpeJobTaskRecordVO> opeJobTaskRecordList = queryOpeJobTaskRecordList(opeJobTaskRecordFilterDTO);

        opeJobTaskRecordList.forEach(opeJobTaskRecordVO -> {
            Timestamp timestamp = new Timestamp(DateUtil.current());
            if (ObjectUtil.isNotNull(opeJobTaskRecordVO.getRestoreTime())) {
                timestamp = opeJobTaskRecordVO.getRestoreTime();
            }
            opeJobTaskRecordVO.setEffectTime((timestamp.getTime() - opeJobTaskRecordVO.getAlarmTime().getTime()) / 1000);
        });
        PageInfo<OpeJobTaskRecordVO> pageInfo = new PageInfo<>(opeJobTaskRecordList);
        PropertyUtils.copyProperties(pageInfo, pageVO, opeJobTaskRecordList);

        return pageVO;
    }

    @Override
    public OpeJobTaskRecordVO queryOpeJobTaskRecordById(Long id) {

        Assert.notNull(id, ResponseEnum.THE_ID_CANNOT_BE_EMPTY.getMessage());

        return this.objectConversion(this.getById(id));
    }

    @Override
    public List<OpeJobTaskAlarmCodeSettingBO> queryOpeJobTaskAlarmCodeSetting(String toolCode) {
        return opeJobTaskRecordMapper.queryOpeJobTaskAlarmCodeSetting(toolCode);
    }

    @Override
    public void saveEapAlarm(JobTaskEapDTO jobTaskEapDTO) {

        Timestamp creationTime = jobTaskEapDTO.getCreationTime();
        if (ObjectUtil.isNull(creationTime)) {
            creationTime = new Timestamp(DateUtil.current());
        }
        LocalDateTime dateTime = creationTime.toLocalDateTime();
        PmShiftManageWithPlanVO response = ResponseUtils.getResponse(pmShiftPlanRemote.queryPmShiftPlanWithManage(dateTime.format(df)));
        String shiftCode = response.getShiftCode();
        String date = response.getDate();

        for (JobTaskAlarmCodeDTO jobTaskAlarmCodeDTO : jobTaskEapDTO.getAlarmCodes()) {
            OpeJobTaskRecord opeJobTaskRecord = new OpeJobTaskRecord();
            opeJobTaskRecord.setToolCode(jobTaskEapDTO.getDeviceCode());
            opeJobTaskRecord.setAlarmCode(jobTaskAlarmCodeDTO.getAlarmCode());

            // 查询报警设置
            List<OpeJobTaskAlarmCodeSettingBO> alarmCodeSettingBOS = opeJobTaskRecordMapper.queryOpeJobTaskAlarmCodeSetting(jobTaskEapDTO.getDeviceCode());
            if (CollectionUtil.isEmpty(alarmCodeSettingBOS)) {
                continue;
            }
            Optional<OpeJobTaskAlarmCodeSettingBO> first = alarmCodeSettingBOS.stream()
                    .filter(alarmCodeSettingBO -> alarmCodeSettingBO.getAlarmCode().equals(jobTaskAlarmCodeDTO.getAlarmCode()))
                    .findFirst();
            if (!first.isPresent()) {
                continue;
            }
            OpeJobTaskAlarmCodeSettingBO opeJobTaskAlarmCodeSettingBO = first.get();
            opeJobTaskRecord.setAlarmMsg(opeJobTaskAlarmCodeSettingBO.getAlarmContent());
            opeJobTaskRecord.setOpeCode(opeJobTaskAlarmCodeSettingBO.getOpeCode());

            // 查询人员配置
            OpeJobTaskStaffingFilterDTO opeJobTaskStaffingFilterDTO = new OpeJobTaskStaffingFilterDTO();
            opeJobTaskStaffingFilterDTO.setToolCode(jobTaskEapDTO.getDeviceCode());
            opeJobTaskStaffingFilterDTO.setShiftCode(shiftCode);
            List<OpeJobTaskStaffingVO> opeJobTaskStaffingVOS = opeJobTaskStaffingService.queryOpeJobTaskStaffingVOList(opeJobTaskStaffingFilterDTO);
            if (CollectionUtil.isEmpty(opeJobTaskStaffingVOS)) {
                continue;
            }
            opeJobTaskRecord.setUserAccount(opeJobTaskStaffingVOS.get(0).getUserAccount());
            opeJobTaskRecord.setUserName(opeJobTaskStaffingVOS.get(0).getUserName());
            opeJobTaskRecord.setStatus(Integer.valueOf(jobTaskAlarmCodeDTO.getStatus()));

            opeJobTaskRecord.setShiftDate(date);
            OpeJobTaskRecord jobTaskRecord = baseMapper.queryOpeJobTaskRecordByAlarmCodeAndToolCode(jobTaskAlarmCodeDTO.getAlarmCode(), jobTaskEapDTO.getDeviceCode());
            if (ObjectUtil.isNull(jobTaskRecord) && Constants.ONE.equals(jobTaskAlarmCodeDTO.getStatus())) {
                opeJobTaskRecord.setCreatedTime(new Timestamp(DateUtil.current()));
                opeJobTaskRecord.setAlarmTime(creationTime);
                baseMapper.insert(opeJobTaskRecord);
                pushPda(opeJobTaskRecord);
                sendMessage(opeJobTaskRecord);
            } else if (ObjectUtil.isNotNull(jobTaskRecord)) {
                jobTaskRecord.setStatus(Integer.valueOf(jobTaskAlarmCodeDTO.getStatus()));
                jobTaskRecord.setUpdatedTime(new Timestamp(DateUtil.current()));
                if (Constants.ONE.equals(jobTaskAlarmCodeDTO.getStatus())) {
                    jobTaskRecord.setAlarmTime(creationTime);
                    pushPda(jobTaskRecord);
                    sendMessage(jobTaskRecord);
                } else {
                    jobTaskRecord.setRestoreTime(creationTime);
                }
                baseMapper.updateById(jobTaskRecord);
            }
        }
    }

    @Override
    public void exportData(OpeJobTaskRecordFilterDTO opeJobTaskRecordFilterDTO, HttpServletResponse response) throws UnsupportedEncodingException {
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("精准推送记录", "UTF-8") + ".xlsx");
        response.setContentType("application/octet-stream");

        OpeJobTaskRecordQuery opeJobTaskRecordQuery = BeanUtils.copyProperties(opeJobTaskRecordFilterDTO, OpeJobTaskRecordQuery.class);
        List<OpeJobTaskRecordVO> opeJobTaskRecordVOS = opeJobTaskRecordMapper.queryOpeJobTaskRecord(opeJobTaskRecordQuery);

        List<OpeJobTaskRecordEO> opeJobTaskRecordEOS = new ArrayList<>();
        opeJobTaskRecordVOS.forEach(opeJobTaskRecordVO -> {
            OpeJobTaskRecordEO opeJobTaskRecordEO = BeanUtil.copyProperties(opeJobTaskRecordVO, OpeJobTaskRecordEO.class, "alarmTime", "restoreTime", "status");
            opeJobTaskRecordEO.setAlarmTime(opeJobTaskRecordVO.getAlarmTime().toLocalDateTime().format(df));
            Timestamp restoreTime = opeJobTaskRecordVO.getRestoreTime();
            Timestamp timestamp = new Timestamp(DateUtil.current());
            if (ObjectUtil.isNotNull(restoreTime)) {
                timestamp = opeJobTaskRecordVO.getRestoreTime();
                opeJobTaskRecordEO.setRestoreTime(restoreTime.toLocalDateTime().format(df));
            }
            opeJobTaskRecordEO.setEffectTime((timestamp.getTime() - opeJobTaskRecordVO.getAlarmTime().getTime()) / 1000);
            opeJobTaskRecordEO.setStatus(opeJobTaskRecordVO.getStatus() == 1 ? "待确认" : "已复位");
            opeJobTaskRecordEOS.add(opeJobTaskRecordEO);
        });
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            EasyExcel.write(outputStream, OpeJobTaskRecordEO.class).sheet("精准推送记录").doWrite(opeJobTaskRecordEOS);
        } catch (Exception e) {
            log.info("exportEarlyWarningFromExcel {}", e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    private void pushPda(OpeJobTaskRecord jobTaskRecord) {
        try {
            String userAccount = jobTaskRecord.getUserAccount();
            String toolCode = jobTaskRecord.getToolCode();
            String[] split = userAccount.split(",");
            PushBatchByAliasDto pushBatchByAliasDto = new PushBatchByAliasDto();
            List<PushBatchByAliasItem> pushBatchByAliasItemList = new ArrayList<>();
            for (String account : split) {
                PushBatchByAliasItem pushBatchByAliasItem = new PushBatchByAliasItem();
                GtPushDTO gtPushDTO = new GtPushDTO();
                gtPushDTO.setTitle("设备故障");
                gtPushDTO.setBody(toolCode + "设备故障，请及时处理");
                pushBatchByAliasItem.setGtPushDTO(gtPushDTO);
                pushBatchByAliasItem.setAliasList(Collections.singletonList(account));
                pushBatchByAliasItemList.add(pushBatchByAliasItem);
            }
            pushBatchByAliasDto.setItemList(pushBatchByAliasItemList);
            log.info("pda推送消息:{}", JSON.toJSONString(pushBatchByAliasDto));
            smsRemote.pushBatchByAlias(pushBatchByAliasDto);
        } catch (Exception e) {
            log.error("推送PDA失败", e);
        }
    }

    private void sendMessage(OpeJobTaskRecord jobTaskRecord) {
        JSONObject param = generateParam(jobTaskRecord);
        SmsDTO sendMessageDto = new SmsDTO.Builder()
                .addTitle("设备离线推送")
                .addContentType("markdown")
                .addMessageTemplateCode("DEVICE_ALARM_SEND")
                .addAccounts(Arrays.asList(jobTaskRecord.getUserAccount().split(",")))
                .addParameters(param)
                .build();
        log.info("设备离线推送请求参数:{}", sendMessageDto);
        ResponseVO<Void> responseVO = smsRemote.sendMessageV2(JSONObject.parseObject(JSON.toJSONString(sendMessageDto)));
        log.info("设备离线推送返回参数:{}", responseVO);
    }

    private JSONObject generateParam(OpeJobTaskRecord jobTaskRecord) {
        JSONObject result = new JSONObject();
        result.put("shiftDate", jobTaskRecord.getShiftDate());
        result.put("lineCode", opeJobTaskRecordMapper.queryToolNameByToolCode(jobTaskRecord.getToolCode()));
        result.put("alarmCode", jobTaskRecord.getAlarmCode());
        result.put("alarmMsg", jobTaskRecord.getAlarmMsg());
        result.put("alarmTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobTaskRecord.getAlarmTime()));
        return result;
    }
}
